import Dysmsapi20170525, * as $Dysmsapi20170525 from '@alicloud/dysmsapi20170525'
import OpenApi, * as $OpenApi from '@alicloud/openapi-client'
import Util, * as $Util from '@alicloud/tea-util'
import * as $tea from '@alicloud/tea-typescript'

import { Context } from 'koa'

import { SmssendException } from '../exception/HttpException'
import commonMiddleware from '../middleware/common'

import { get, post, controller, use, unifyUse } from '../router/decorator/index'
import response from '../../utils/response'
import config from '../config'
import { generateRandomCode } from '../../utils/sms'
import { validateChinesePhoneNumber } from '../../utils/validate'
import redis from '../db/redis'

/** 装饰器router class */
export type RouterController<T extends string> = {
  [key in T]: (ctx: Context) => Promise<void>
}

type MethodName = 'getName' | 'postName'

/**
 * SMS controller class, handles SMS related operations
 */
@controller('/sms')
@unifyUse<MethodName>(commonMiddleware)
class Sms {
  private static clientInstance: Dysmsapi20170525 | null = null

  /**
   * @remarks
   * 使用AK&SK初始化账号Client，支持单例模式
   * @returns Client
   *
   * @throws Exception
   */
  static createClient(): Dysmsapi20170525 {
    if (this.clientInstance) return this.clientInstance

    const accessKeyId = process.env['ALIBABA_CLOUD_ACCESS_KEY_ID']
    const accessKeySecret = process.env['ALIBABA_CLOUD_ACCESS_KEY_SECRET']
    const endpoint =
      process.env['ALIBABA_CLOUD_ENDPOINT'] || 'dysmsapi.aliyuncs.com'

    if (!accessKeyId || !accessKeySecret) {
      throw new Error(
        'Missing required environment variables: ALIBABA_CLOUD_ACCESS_KEY_ID or ALIBABA_CLOUD_ACCESS_KEY_SECRET'
      )
    }

    const config = new $OpenApi.Config({
      accessKeyId,
      accessKeySecret
    })
    config.endpoint = endpoint

    this.clientInstance = new Dysmsapi20170525(config)
    return this.clientInstance
  }

  /**
   * Main function for sending SMS using command line arguments
   * 使用命令行发送短信
   * @param args Command line arguments
   */
  static async main(args: string[]): Promise<void> {
    try {
      const client = Sms.createClient()
      const sendSmsRequest = new $Dysmsapi20170525.SendSmsRequest({
        signName: config.sms.signName,
        templateCode: config.sms.templateCode,
        phoneNumbers: '15161255100',
        templateParam: '{"code":"1234"}'
      })

      const result = await client.sendSmsWithOptions(
        sendSmsRequest,
        new $Util.RuntimeOptions({})
      )
      console.log(result)
    } catch (error: any) {
      console.error('Error occurred:', error.message)
      if (error.data && error.data['Recommend']) {
        console.error('Diagnostic information:', error.data['Recommend'])
      }
    }
  }

  /**
   * API endpoint for sending SMS
   * 发送短信
   * @param ctx Koa context
   */
  @post('/sendSms')
  async sendSms(ctx: Context): Promise<void> {
    // 统一输入参数校验
    const { phoneNumbers } = ctx.request.body

    if (!validateChinesePhoneNumber(phoneNumbers)) {
      throw new SmssendException('', '手机号码格式不正确', 20002)
    }

    // 参数校验
    if (typeof phoneNumbers !== 'string' && !Array.isArray(phoneNumbers)) {
      return response.failResponse(
        ctx,
        'Invalid phoneNumbers parameter. It should be a string or an array of strings.'
      )
    }

    try {
      let phoneNumberString: string
      if (typeof phoneNumbers === 'string') {
        phoneNumberString = phoneNumbers.trim() // 如果是字符串，直接使用
      } else if (Array.isArray(phoneNumbers)) {
        phoneNumberString = phoneNumbers.join(',') // 如果是数组，拼接为字符串
      } else {
        throw new SmssendException(
          '',
          'Invalid phoneNumbers format after validation.',
          210001
        )
      }

      // 动态生成验证码
      const code = generateRandomCode(4) // 假设生成4位随机验证码
      const formattedTemplateParam = JSON.stringify({ code })

      // 修改 Redis 键名，将手机号作为键名的一部分
      const redisKey = `smsCode:${phoneNumberString}`
      await redis.setex(redisKey, 60, code)
      console.log('验证码已保存到 Redis')

      const storedCode = await redis.get(redisKey)
      console.log('从 Redis 获取的验证码：', storedCode)

      // return response.success(ctx, {
      //   smscode: code,
      //   phoneNumberString: phoneNumberString
      // })

      // 构造请求数据
      const sendSmsRequestData = {
        signName: config.sms.signName,
        templateCode: config.sms.templateCode,
        templateParam: formattedTemplateParam,
        phoneNumbers: phoneNumberString // 使用处理后的字符串
      }

      console.log('发送短信请求数据：', sendSmsRequestData)

      // 创建客户端并发送短信
      const client = Sms.createClient()
      const sendSmsRequest = new $Dysmsapi20170525.SendSmsRequest(
        sendSmsRequestData
      )

      const runtime = new $Util.RuntimeOptions({})

      const result = await client.sendSmsWithOptions(sendSmsRequest, runtime)

      // 确保 result.body 不为 undefined
      if (!result.body) {
        throw new SmssendException(
          '',
          'SMS service returned an empty response body.',
          210003
        )
      }

      // 如果 result.body 存在，则安全地扩展其内容
      Object.assign(result.body || {}, { smscode: code })

      // 如果发送失败，抛出异常
      if (result.body?.code !== 'OK') {
        throw new SmssendException(
          '',
          `Failed to send SMS. Code: ${result.body?.code}, Message: ${result.body?.message}`
        )
      }

      // 返回成功响应
      response.success(ctx, result.body)
    } catch (error: any) {
      // 记录日志
      console.error('Error sending SMS:', '----')
      // 增强异常处理
      if (error.data && error.data['Recommend']) {
        console.error('Diagnostic information:', error.data['Recommend'], '###')
      }

      // 向用户返回友好的错误信息
      throw new SmssendException('', error.msg, 20005)
    }
  }

  // 辅助函数：生成随机验证码
  @get('/getSms')
  async getSms(ctx: Context): Promise<void> {
    try {
      // 写入 Redis
      await ctx.redis.set('key', 'Hello Redis')

      // 读取 Redis
      const value = await ctx.redis.get('key')

      ctx.body = {
        data: value
      }
    } catch (error) {
      // 捕获异常并返回错误信息
      ctx.status = 500
      ctx.body = {
        error: 'Internal Server Error',
        message: (error as Error).message
      }
    }
  }
}

export default Sms

// console.log('Starting SMS service...', process.argv)
// Sms.main(process.argv.slice(2))
